package com.evil.application.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.application.mapper.ControlPermissionMapper;
import com.evil.application.pojo.dto.permission.control.ControlPermissionDTO;
import com.evil.application.pojo.dto.permission.control.ModifyControlPermissionReqDTO;
import com.evil.application.pojo.entity.ControlPermission;
import com.evil.application.service.ControlPermissionService;
import com.evil.common.application.dto.permission.control.ControlPermissionSourceDTO;
import com.evil.common.application.dto.permission.control.ControlPermissionsReqDTO;
import com.evil.common.application.dto.permission.control.CopyControlPermissionReqDTO;
import com.evil.common.application.enums.form.ControlPermissionSourceTypeEnum;
import com.evil.common.application.enums.permission.ControlVisibleEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 控件权限配置表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ControlPermissionServiceImpl extends ServiceImpl<ControlPermissionMapper, ControlPermission> implements ControlPermissionService {

    private final ApplicationLogServiceImpl logService;

    /**
     * 保存控件权限
     *
     * @param modifyControlPermissionReqDTO modifyControlPermissionReqDTO
     */
    @Override
    public void saveControlPermissions(ModifyControlPermissionReqDTO modifyControlPermissionReqDTO) {
        Long enterpriseId = modifyControlPermissionReqDTO.getEnterpriseId();
        ControlPermissionSourceDTO controlPermissionSourceDTO = modifyControlPermissionReqDTO.getControlPermissionSourceDTO();
        List<ControlPermissionDTO> controlPermissions = modifyControlPermissionReqDTO.getControlPermissions();
        Collection<Long> controlIds = modifyControlPermissionReqDTO.getControlIds();

        // 源类型
        Integer sourceType = controlPermissionSourceDTO.getSourceType();
        Long sourceId = controlPermissionSourceDTO.getSourceId();
        ControlPermissionSourceTypeEnum controlPermissionSourceTypeEnum = ControlPermissionSourceTypeEnum.isExistById(sourceType);

        Map<Long, ControlPermissionDTO> controlPermissionMap = StreamUtil.toMapK(controlPermissions, ControlPermissionDTO::getControlId);
        // 检验节点控件配置参数
        if (!controlIds.containsAll(controlPermissionMap.keySet())) {
            throw new BusinessException(RCodeEnum.ERROR_PARAMETER, String.format("%s，表单控件不存在", controlPermissionSourceTypeEnum.getName()));
        }

        // 节点控件配置列表
        List<ControlPermission> dbControlPermissions = this.baseMapper.findBySource(controlPermissionSourceDTO);
        Map<Long, ControlPermission> dbControlPermissionMap = StreamUtil.toMapK(dbControlPermissions, ControlPermission::getControlId);

        // 补充缺失的权限
        controlIds.forEach(controlId -> {
            if (!controlPermissionMap.containsKey(controlId)) {
                ControlPermissionDTO p;
                if (dbControlPermissionMap.containsKey(controlId)) {
                    p = new ControlPermissionDTO(dbControlPermissionMap.get(controlId));
                } else {
                    p = new ControlPermissionDTO(controlId);
                }
                controlPermissions.add(p);
            }
        });

        // 编辑/新增
        List<ControlPermission> modifies = new ArrayList<>();
        for (int i = 0; i < controlPermissions.size(); i++) {
            ControlPermissionDTO controlPermissionDTO = controlPermissions.get(i);

            Long controlId = controlPermissionDTO.getControlId();
            ControlPermission controlPermission;
            if (dbControlPermissionMap.containsKey(controlId)) {
                // 编辑
                controlPermission = dbControlPermissionMap.get(controlId);
            } else {
                // 新增
                controlPermission = this.createControlPermission(enterpriseId, sourceType, sourceId, controlPermissionDTO.getControlId());
            }
            controlPermission.setSort(i);
            controlPermission.setVisible(controlPermissionDTO.getVisible());
            modifies.add(controlPermission);
        }

        // 删除
        modifies.addAll(dbControlPermissions.stream()
                .filter(e -> !controlPermissionMap.containsKey(e.getControlId()))
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList()));

        logService.saveAndCheck(this.baseMapper, ControlPermission::getControlPermissionId, modifies);
    }

    /**
     * 复制控件权限
     *
     * @param controlPermissionReqDTO controlPermissionReqDTO
     */
    @Override
    public void copyControlPermissions(CopyControlPermissionReqDTO controlPermissionReqDTO) {
        Long enterpriseId = controlPermissionReqDTO.getEnterpriseId();
        ControlPermissionSourceDTO source = controlPermissionReqDTO.getSource();
        ControlPermissionSourceDTO target = controlPermissionReqDTO.getTarget();
        Map<Long, Long> controlIdMap = controlPermissionReqDTO.getControlIdMap();

        List<ControlPermission> sourceList = this.baseMapper.findBySource(source);
        List<ControlPermission> targetList = this.baseMapper.findBySource(target);

        Map<Long, ControlPermission> targetMap = StreamUtil.toMapK(targetList, ControlPermission::getControlId);

        List<ControlPermission> modifies = new ArrayList<>();
        List<Long> controlIds = new ArrayList<>();
        for (int i = 0; i < sourceList.size(); i++) {
            ControlPermission sourcePermission = sourceList.get(i);
            if (controlIdMap.containsKey(sourcePermission.getControlId())) {
                // 有效控件
                Long controlId = controlIdMap.get(sourcePermission.getControlId());

                ControlPermission copyPermission;
                if (targetMap.containsKey(controlId)) {
                    // 编辑
                    copyPermission = targetMap.get(controlId);
                } else {
                    // 新增
                    copyPermission = this.createControlPermission(enterpriseId, target.getSourceType(), target.getSourceId(), controlId);
                }
                copyPermission.setSort(i);
                copyPermission.setVisible(sourcePermission.getVisible());
                copyPermission.setAddStatus(sourcePermission.getAddStatus());
                copyPermission.setModifyStatus(sourcePermission.getModifyStatus());
                copyPermission.setDeleteStatus(sourcePermission.getDeleteStatus());

                modifies.add(copyPermission);
                controlIds.add(copyPermission.getControlId());
            }
        }

        // 删除
        modifies.addAll(targetList.stream()
                .filter(e -> !controlIds.contains(e.getControlId()))
                .peek(e -> e.setIsDeleted(SwitchEnum.NO.getId()))
                .collect(Collectors.toList()));

        logService.saveAndCheck(this.baseMapper, ControlPermission::getControlPermissionId, modifies);
    }

    /**
     * 删除控件权限
     *
     * @param controlPermissionsReqDTO controlPermissionsReqDTO
     */
    @Override
    public void deleteControlPermissions(ControlPermissionsReqDTO controlPermissionsReqDTO) {
        List<ControlPermission> deletedList = this.baseMapper.findByControlPermissions(controlPermissionsReqDTO).stream()
                .peek(e -> e.setIsDeleted(SwitchEnum.NO.getId()))
                .collect(Collectors.toList());
        logService.saveAndCheck(this.baseMapper, ControlPermission::getControlPermissionId, deletedList);
    }

    /**
     * 获取控件权限基础信息
     *
     * @param controlPermissionSourceDTO controlPermissionSourceDTO
     * @return List
     */
    @Override
    public List<ControlPermissionDTO> findBasesBySource(ControlPermissionSourceDTO controlPermissionSourceDTO) {
        List<ControlPermission> permissions = this.baseMapper.findBySource(controlPermissionSourceDTO);
        return this.supplyControlPermissions(permissions, controlPermissionSourceDTO.getControlIds());
    }

    /**
     * 获取节点控件权限
     *
     * @param nodeId     nodeId
     * @param controlIds controlIds
     * @return List
     */
    @Override
    public List<ControlPermissionDTO> nodeControlPermissions(Long nodeId, Collection<Long> controlIds) {
        ControlPermissionSourceDTO permissionReqDTO = new ControlPermissionSourceDTO(ControlPermissionSourceTypeEnum.PROCESS_NODE, nodeId);
        // 控件权限 补充完整
        return this.supplyControlPermissions(this.baseMapper.findBySource(permissionReqDTO), controlIds);
    }

    /**
     * 获取节点控件权限
     *
     * @param nodeIds           nodeIds
     * @param nodeControlIdsMap nodeControlIdsMap
     * @return List
     */
    @Override
    public List<ControlPermissionDTO> nodesControlPermissions(Collection<Long> nodeIds, Map<Long, Set<Long>> nodeControlIdsMap) {
        ControlPermissionsReqDTO permissionsReqDTO = new ControlPermissionsReqDTO(ControlPermissionSourceTypeEnum.PROCESS_NODE, nodeIds);
        List<ControlPermissionDTO> controlPermissions = new ArrayList<>();
        this.supplyControlPermissions(permissionsReqDTO, nodeControlIdsMap).forEach((key, value) -> controlPermissions.addAll(value));
        return controlPermissions;
    }

    /**
     * 获取节点控件权限
     *
     * @param nodeIds           nodeIds
     * @param nodeControlIdsMap nodeControlIdsMap
     * @return Map
     */
    @Override
    public Map<Long, List<ControlPermissionDTO>> nodesControlPermissionMap(Collection<Long> nodeIds, Map<Long, Set<Long>> nodeControlIdsMap) {
        ControlPermissionsReqDTO permissionsReqDTO = new ControlPermissionsReqDTO(ControlPermissionSourceTypeEnum.PROCESS_NODE, nodeIds);
        return this.supplyControlPermissions(permissionsReqDTO, nodeControlIdsMap);
    }

    /**
     * 获取节点可见控件权限
     *
     * @param nodeIds           nodeIds
     * @param nodeControlIdsMap nodeControlIdsMap
     * @return Map
     */
    @Override
    public Map<Long, List<Long>> nodesVisibleControlPermissionMap(Collection<Long> nodeIds, Map<Long, Set<Long>> nodeControlIdsMap) {
        Map<Long, List<Long>> nodeVisibleControlIdsMap = new HashMap<>();
        this.nodesControlPermissionMap(nodeIds, nodeControlIdsMap)
                .forEach((nodeId, controlPermissions) -> controlPermissions.forEach(s -> {
                    if (ControlVisibleEnum.INVISIBLE.getId() != s.getVisible()) {
                        // 节点可见控件
                        List<Long> nodeControlIds = nodeVisibleControlIdsMap.getOrDefault(nodeId, new ArrayList<>());
                        nodeControlIds.add(s.getControlId());
                        nodeVisibleControlIdsMap.put(nodeId, nodeControlIds);
                    }
                }));
        return nodeVisibleControlIdsMap;
    }

    /**
     * 控件权限(缺失会补充完整)
     *
     * @param controlPermissions controlPermissions
     * @param sourceControlIds   sourceControlIds
     * @return List
     */
    @Override
    public List<ControlPermissionDTO> supplyControlPermissions(List<ControlPermission> controlPermissions, Collection<Long> sourceControlIds) {
        if (Objects.isNull(sourceControlIds)) {
            // 不需要补充
            return controlPermissions.stream().map(ControlPermissionDTO::new).collect(Collectors.toList());
        }
        // 补充完整控件
        Map<Long, ControlPermission> controlPermissionMap = StreamUtil.toMapK(controlPermissions, ControlPermission::getControlId);
        return sourceControlIds.stream().map(controlId -> {
            if (controlPermissionMap.containsKey(controlId)) {
                return new ControlPermissionDTO(controlPermissionMap.get(controlId));
            } else {
                return new ControlPermissionDTO(controlId);
            }
        }).collect(Collectors.toList());
    }

    /**
     * 创建控件配置
     *
     * @param enterpriseId enterpriseId
     * @param sourceType   sourceType
     * @param controlId    controlId
     * @return NodeControlSetting
     */
    private ControlPermission createControlPermission(Long enterpriseId, Integer sourceType, Long sourceId, Long controlId) {
        ControlPermission applicationControlPermission = new ControlPermission();
        applicationControlPermission.setEnterpriseId(enterpriseId);
        applicationControlPermission.setSourceType(sourceType);
        applicationControlPermission.setSourceId(sourceId);
        applicationControlPermission.setControlId(controlId);
        applicationControlPermission.setVisible(ControlVisibleEnum.EDIT.getId());
        applicationControlPermission.setIsDeleted(SwitchEnum.NO.getId());

        return applicationControlPermission;
    }

    /**
     * 控件权限(缺失会补充完整)
     *
     * @param controlPermissionsReqDTO controlPermissionsReqDTO
     * @param sourceControlIdsMap      sourceControlIdsMap
     * @return Map
     */
    public Map<Long, List<ControlPermissionDTO>> supplyControlPermissions(ControlPermissionsReqDTO controlPermissionsReqDTO, Map<Long, Set<Long>> sourceControlIdsMap) {
        Integer sourceType = controlPermissionsReqDTO.getSourceType();
        Collection<Long> sourceIds = controlPermissionsReqDTO.getSourceIds();

        // 源信息 分组
        Map<String, List<ControlPermission>> sourceControlPermissionsMap = StreamUtil.toMapKV(sourceIds,
                e -> this.generateSourceKey(sourceType, e), e -> new ArrayList<>());

        sourceControlPermissionsMap.putAll(StreamUtil.groupK(this.baseMapper.findByControlPermissions(controlPermissionsReqDTO), this::generateSourceKey));

        Map<Long, List<ControlPermissionDTO>> result = new HashMap<>();
        sourceControlPermissionsMap.forEach((key, permissions) -> {
            Long sourceId = this.reductionSourceKey(key);
            // 源控件列表
            Set<Long> sourceControlIds = sourceControlIdsMap.getOrDefault(sourceId, new HashSet<>());
            // 补充控件权限
            List<ControlPermissionDTO> controlPermissions = this.supplyControlPermissions(permissions, sourceControlIds);
            result.put(sourceId, controlPermissions);
        });
        return result;
    }

    private String generateSourceKey(ControlPermission permission) {
        return this.generateSourceKey(permission.getSourceType(), permission.getSourceId());
    }

    private String generateSourceKey(Integer sourceType, Long sourceId) {
        return String.format("%s_%s", sourceType, sourceId);
    }

    private Long reductionSourceKey(String sourceKey) {
        return Long.valueOf(sourceKey.split("_")[1]);
    }
}
